出处:ObjectX 博客
原作者:ObjectX
call 只会执行 Parent1 构造函数,并将 this 绑定到 Child1 实例上。因此,Parent1 构造函数内部的属性会被拷贝到 Child1 的实例中,但 Parent1.prototype 上的方法不会被继承
function Parent1() {
this.name = 'parent1';
}
function Child1() {
Parent1.call(this);
this.type = 'child1';
}
console.log(new Child1());
call 只会执行 Parent1 构造函数,并将 this 绑定到 Child1 实例上。因此,Parent1 构造函数内部的属性会被拷贝到 Child1 的实例中,但 Parent1.prototype 上的方法不会被继承
由于 call 只是在 Child1 的构造函数内执行 Parent1,所以 Parent1.prototype 上的方法不会被继承
通过 Child2.prototype = new Parent2(); 让 Child2 继承 Parent2,这样 Child2 的实例可以访问 Parent2.prototype 上的方法
function Parent2() {
this.name = 'parent2';
this.play = [1, 2, 3];
}
Parent2.prototype.greet = function() {
console.log('Hello from prototype');
};
function Child2() {
this.type = 'child2';
}
Child2.prototype = new Parent2();
const c1 = new Child2();
const c2 = new Child2();
c1.play.push(4);
console.log(c1.play); // [1, 2, 3, 4]
console.log(c2.play); // [1, 2, 3, 4] (预期每个实例应有独立的 play 数组)
由于 Child2.prototype = new Parent2();,Child2 的实例可以访问 Parent2.prototype 上的方法,同时 Child2 的所有实例会共享 Parent2 构造函数内定义的引用类型属性。
Child2.prototype = new Parent2(); 会导致 Parent2 的所有实例共享 play 数组play 也会影响其他实例Parent3.call(this) 继承实例属性(避免父类构造函数的引用类型属性共享)Child3.prototype = new Parent3() 继承原型属性和方法function Parent3() {
this.name = 'parent3';
this.play = [1, 2, 3];
}
function Child3() {
Parent3.call(this);
this.type = 'child3';
}
Child3.prototype = new Parent3();
const s3 = new Child3();
const s4 = new Child3();
s3.play.push(4);
console.log(s3.play); // [1, 2, 3, 4]
console.log(s4.play); // [1, 2, 3]
通过 Parent3.call(this); 继承实例属性,Child3.prototype = new Parent3(); 继承方法。这样每个实例都有自己的 play 数组,不会互相影响
Child3.prototype = new Parent3(); 这一行会导致 Parent3 的构造函数被执行两次直接让 Child4.prototype 指向 Parent4.prototype,这样减少了一次 Parent4 的构造函数调用
function Parent4() {
this.name = 'parent4';
this.play = [1, 2, 3];
}
function Child4() {
Parent4.call(this);
this.type = 'child4';
}
Child4.prototype = Parent4.prototype;
const s3 = new Child4();
const s4 = new Child4();
console.log(s3);
这样做的好处是减少了一次 Parent4 的构造函数调用,但 Child4 的 constructor 会错误地指向 Parent4
Child4.prototype.constructor 指向 Parent4,而不是 Child4child 原型对象是同一个,还是有引用问题Child4.prototype = Parent4.prototype; 时,Child4.prototype 被赋值为 Parent4.prototype,这意味着 Child4 的原型对象指向 Parent4 的原型Child4.prototype.constructor 的值也会被改变。因为原型对象 Parent4.prototype 中有一个 constructor 属性,指向的是 Parent4 构造函数。由于 Child4.prototype 被指向 Parent4.prototype,所以 Child4.prototype.constructor 会继承 Parent4.prototype.constructor,而不再是 Child4 构造函数使用 Object.create 创建 Child5.prototype,避免 Parent5 的构造函数被执行两次,并修正 constructor
function Parent5() {
this.name = 'parent5';
this.play = [1, 2, 3];
}
function Child5() {
Parent5.call(this);
this.type = 'child5';
}
Child5.prototype = Object.create(Parent5.prototype);
Child5.prototype.constructor = Child5;
const child = new Child5();
console.log(child);
console.log(child.constructor); // Child5
Object.create(Parent5.prototype) 创建一个新的对象,并让其 __proto__ 指向 Parent5.prototype。这里就实现了原型链Child5.prototype.constructor = Child5; 修正 constructor 指向constructor 指向正确call 继承实例属性,通过 new Parent() 继承原型方法,但会导致父类构造函数执行两次Parent.prototype 赋值给 Child.prototype,但 constructor 会指向错误Object.create 继承原型,避免两次调用构造函数,同时修正 constructor,是 ES5 继承的最佳方案